home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DDJ0192.ARJ / EDITBOX.C < prev    next >
Text File  |  1991-10-23  |  36KB  |  1,123 lines

  1. /* ------------- editbox.c ------------ */
  2. #include "dflat.h"
  3.  
  4. #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITLEN : ENTRYLEN)
  5. #define SetLinePointer(wnd, ln) (wnd->CurrLine = ln)
  6. #define isWhite(c)     ((c)==' '||(c)=='\n')
  7. /* ---------- local prototypes ----------- */
  8. static void SaveDeletedText(WINDOW, char *, int);
  9. static void Forward(WINDOW);
  10. static void Backward(WINDOW);
  11. static void End(WINDOW);
  12. static void Home(WINDOW);
  13. static void Downward(WINDOW);
  14. static void Upward(WINDOW);
  15. static void StickEnd(WINDOW);
  16. static void NextWord(WINDOW);
  17. static void PrevWord(WINDOW);
  18. static void ResetEditBox(WINDOW);
  19. static void ModTextPointers(WINDOW, int, int);
  20. /* -------- local variables -------- */
  21. static int KeyBoardMarking, ButtonDown;
  22. static int TextMarking;
  23. static int ButtonX, ButtonY;
  24. static int PrevY = -1;
  25.  
  26. /* ----------- CREATE_WINDOW Message ---------- */
  27. static int CreateWindowMsg(WINDOW wnd)
  28. {
  29.     int rtn = BaseWndProc(EDITBOX, wnd, CREATE_WINDOW, 0, 0);
  30.     wnd->MaxTextLength = MAXTEXTLEN+1;
  31.     wnd->textlen = EditBufLen(wnd);
  32.     wnd->InsertMode = TRUE;
  33.     ResetEditBox(wnd);
  34.     return rtn;
  35. }
  36. /* ----------- SETTEXT Message ---------- */
  37. static int SetTextMsg(WINDOW wnd, PARAM p1)
  38. {
  39.     int rtn = FALSE;
  40.     if (strlen((char *)p1) <= wnd->MaxTextLength)    {
  41.         rtn = BaseWndProc(EDITBOX, wnd, SETTEXT, p1, 0);
  42.         wnd->CurrLine = 0;
  43.     }
  44.     return rtn;
  45. }
  46. /* ----------- ADDTEXT Message ---------- */
  47. static int AddTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  48. {
  49.     int rtn = FALSE;
  50.     if (strlen((char *)p1)+wnd->textlen <= wnd->MaxTextLength) {
  51.         rtn = BaseWndProc(EDITBOX, wnd, ADDTEXT, p1, p2);
  52.         if (rtn != FALSE)    {
  53.             if (!isMultiLine(wnd))    {
  54.                 wnd->CurrLine = 0;
  55.                 wnd->CurrCol = strlen((char *)p1);
  56.                 if (wnd->CurrCol >= ClientWidth(wnd))    {
  57.                     wnd->wleft = wnd->CurrCol-ClientWidth(wnd);
  58.                     wnd->CurrCol -= wnd->wleft;
  59.                 }
  60.                 wnd->BlkEndCol = wnd->CurrCol;
  61.                 SendMessage(wnd, KEYBOARD_CURSOR,
  62.                                      WndCol, wnd->WndRow);
  63.             }
  64.         }
  65.     }
  66.     return rtn;
  67. }
  68. /* ----------- GETTEXT Message ---------- */
  69. static int GetTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  70. {
  71.     char *cp1 = (char *)p1;
  72.     char *cp2 = wnd->text;
  73.     if (cp2 != NULL)    {
  74.         while (p2-- && *cp2 && *cp2 != '\n')
  75.             *cp1++ = *cp2++;
  76.         *cp1 = '\0';
  77.         return TRUE;
  78.     }
  79.     return FALSE;
  80. }
  81. /* ----------- SETTEXTLENGTH Message ---------- */
  82. static int SetTextLengthMsg(WINDOW wnd, unsigned int len)
  83. {
  84.     if (++len < MAXTEXTLEN)    {
  85.         wnd->MaxTextLength = len;
  86.         if (len < wnd->textlen)    {
  87.             if ((wnd->text=realloc(wnd->text, len+2)) != NULL) {
  88.                 wnd->textlen = len;
  89.                 *((wnd->text)+len) = '\0';
  90.                 *((wnd->text)+len+1) = '\0';
  91.                 BuildTextPointers(wnd);
  92.             }
  93.         }
  94.         return TRUE;
  95.     }
  96.     return FALSE;
  97. }
  98. /* ----------- KEYBOARD_CURSOR Message ---------- */
  99. static int KeyboardCursorMsg(WINDOW wnd, PARAM p1, PARAM p2)
  100. {
  101.     int rtn;
  102.     wnd->CurrCol = (int)p1 + wnd->wleft;
  103.     wnd->WndRow = (int)p2;
  104.     wnd->CurrLine = (int)p2 + wnd->wtop;
  105.     rtn = BaseWndProc(EDITBOX, wnd, KEYBOARD_CURSOR, p1, p2);
  106.     if (wnd == inFocus && CharInView(wnd, (int)p1, (int)p2))
  107.         SendMessage(NULL, SHOW_CURSOR, wnd->InsertMode, 0);
  108.     else SendMessage(NULL, HIDE_CURSOR, 0, 0);
  109.     return rtn;
  110. }
  111. /* ----------- SIZE Message ---------- */
  112. int SizeMsg(WINDOW wnd, PARAM p1, PARAM p2)
  113. {
  114.     int rtn = BaseWndProc(EDITBOX, wnd, SIZE, p1, p2);
  115.     if (WndCol > ClientWidth(wnd)-1)
  116.         wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft;
  117.     if (wnd->WndRow > ClientHeight(wnd)-1)    {
  118.         wnd->WndRow = ClientHeight(wnd)-1;
  119.         SetLinePointer(wnd, wnd->WndRow+wnd->wtop);
  120.     }
  121.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  122.     return rtn;
  123. }
  124. /* ----------- SCROLL Message ---------- */
  125. static int ScrollMsg(WINDOW wnd, PARAM p1)
  126. {
  127.     int rtn = FALSE;
  128.     if (isMultiLine(wnd))    {
  129.         rtn = BaseWndProc(EDITBOX,wnd,SCROLL,p1,0);
  130.         if (rtn != FALSE)    {
  131.             if (p1)    {
  132.                 /* -------- scrolling up --------- */
  133.                 if (wnd->WndRow == 0)    {
  134.                     wnd->CurrLine++;
  135.                     StickEnd(wnd);
  136.                 }
  137.                 else
  138.                     --wnd->WndRow;
  139.             }
  140.             else    {
  141.                 /* -------- scrolling down --------- */
  142.                 if (wnd->WndRow == ClientHeight(wnd)-1)    {
  143.                     if (wnd->CurrLine > 0)
  144.                         --wnd->CurrLine;
  145.                     StickEnd(wnd);
  146.                 }
  147.                 else
  148.                     wnd->WndRow++;
  149.             }
  150.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  151.         }
  152.     }
  153.     return rtn;
  154. }
  155. /* ----------- HORIZSCROLL Message ---------- */
  156. static int HorizScrollMsg(WINDOW wnd, PARAM p1)
  157. {
  158.     int rtn = FALSE;
  159.     char *currchar = CurrChar;
  160.     if (!(p1 &&
  161.             wnd->CurrCol == wnd->wleft && *currchar == '\n'))  {
  162.         rtn = BaseWndProc(EDITBOX, wnd, HORIZSCROLL, p1, 0);
  163.         if (rtn != FALSE)    {
  164.             if (wnd->CurrCol < wnd->wleft)
  165.                 wnd->CurrCol++;
  166.             else if (WndCol == ClientWidth(wnd))
  167.                 --wnd->CurrCol;
  168.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  169.         }
  170.     }
  171.     return rtn;
  172. }
  173. /* ----------- SCROLLPAGE Message ---------- */
  174. static int ScrollPageMsg(WINDOW wnd, PARAM p1)
  175. {
  176.     int rtn = FALSE;
  177.     if (isMultiLine(wnd))    {
  178.         rtn = BaseWndProc(EDITBOX, wnd, SCROLLPAGE, p1, 0);
  179.         SetLinePointer(wnd, wnd->wtop+wnd->WndRow);
  180.         StickEnd(wnd);
  181.         SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow);
  182.     }
  183.     return rtn;
  184. }
  185. /* ----------- HORIZSCROLLPAGE Message ---------- */
  186. static int HorizPageMsg(WINDOW wnd, PARAM p1)
  187. {
  188.     int rtn = BaseWndProc(EDITBOX, wnd, HORIZPAGE, p1, 0);
  189.     if ((int) p1 == FALSE)    {
  190.         if (wnd->CurrCol > wnd->wleft+ClientWidth(wnd)-1)
  191.             wnd->CurrCol = wnd->wleft+ClientWidth(wnd)-1;
  192.     }
  193.     else if (wnd->CurrCol < wnd->wleft)
  194.         wnd->CurrCol = wnd->wleft;
  195.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  196.     return rtn;
  197. }
  198. /* ----- Extend the marked block to the new x,y position ---- */
  199. static void ExtendBlock(WINDOW wnd, int x, int y)
  200. {
  201.     int bbl, bel;
  202.     int ptop = min(wnd->BlkBegLine, wnd->BlkEndLine);
  203.     int pbot = max(wnd->BlkBegLine, wnd->BlkEndLine);
  204.     char *lp = TextLine(wnd, wnd->wtop+y);
  205.     int len = (int) (strchr(lp, '\n') - lp);
  206.     x = min(x, len-wnd->wleft);
  207.     wnd->BlkEndCol = x+wnd->wleft;
  208.     wnd->BlkEndLine = y+wnd->wtop;
  209.     bbl = min(wnd->BlkBegLine, wnd->BlkEndLine);
  210.     bel = max(wnd->BlkBegLine, wnd->BlkEndLine);
  211.     while (ptop < bbl)    {
  212.         WriteTextLine(wnd, NULL, ptop, FALSE);
  213.         ptop++;
  214.     }
  215.     for (y = bbl; y <= bel; y++)
  216.         WriteTextLine(wnd, NULL, y, FALSE);
  217.     while (pbot > bel)    {
  218.         WriteTextLine(wnd, NULL, pbot, FALSE);
  219.         --pbot;
  220.     }
  221. }
  222. /* ----------- LEFT_BUTTON Message ---------- */
  223. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  224. {
  225.     int MouseX = (int) p1 - GetClientLeft(wnd);
  226.     int MouseY = (int) p2 - GetClientTop(wnd);
  227.     RECT rc = ClientRect(wnd);
  228.     char *lp;
  229.     int len;
  230.     if (KeyBoardMarking)
  231.         return TRUE;
  232.     if (WindowMoving || WindowSizing)
  233.         return FALSE;
  234.     if (isMultiLine(wnd))    {
  235.         if (TextMarking)    {
  236.             if (!InsideRect(p1, p2, rc))    {
  237.                 if ((int)p1 == GetLeft(wnd))
  238.                     if (SendMessage(wnd, HORIZSCROLL, 0, 0))
  239.                         ExtendBlock(wnd, MouseX-1, MouseY);
  240.                 if ((int)p1 == GetRight(wnd))
  241.                     if (SendMessage(wnd, HORIZSCROLL, TRUE, 0))
  242.                         ExtendBlock(wnd, MouseX+1, MouseY);
  243.                 if ((int)p2 == GetTop(wnd))
  244.                     if (SendMessage(wnd, SCROLL, FALSE, 0))
  245.                         ExtendBlock(wnd, MouseX, MouseY+1);
  246.                 if ((int)p2 == GetBottom(wnd))
  247.                     if (SendMessage(wnd, SCROLL, TRUE, 0))
  248.                         ExtendBlock(wnd, MouseX, MouseY-1);
  249.                 SendMessage(wnd, PAINT, 0, 0);
  250.             }
  251.             return TRUE;
  252.         }
  253.         if (!InsideRect(p1, p2, rc))
  254.             return FALSE;
  255.         if (TextBlockMarked(wnd))    {
  256.             ClearTextBlock(wnd);
  257.             SendMessage(wnd, PAINT, 0, 0);
  258.         }
  259.         if (wnd->wlines)    {
  260.             if (MouseY > wnd->wlines-1)
  261.                 return TRUE;
  262.             lp = TextLine(wnd, MouseY+wnd->wtop);
  263.             len = (int) (strchr(lp, '\n') - lp);
  264.             MouseX = min(MouseX, len);
  265.             if (MouseX < wnd->wleft)    {
  266.                 MouseX = 0;
  267.                 SendMessage(wnd, KEYBOARD, HOME, 0);
  268.             }
  269.             ButtonDown = TRUE;
  270.             ButtonX = MouseX;
  271.             ButtonY = MouseY;
  272.         }
  273.         else
  274.             MouseX = MouseY = 0;
  275.         wnd->WndRow = MouseY;
  276.         SetLinePointer(wnd, MouseY+wnd->wtop);
  277.     }
  278.     if (isMultiLine(wnd) ||
  279.         (!TextBlockMarked(wnd)
  280.             && MouseX+wnd->wleft < strlen(wnd->text)))
  281.         wnd->CurrCol = MouseX+wnd->wleft;
  282.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  283.     return TRUE;
  284. }
  285. /* ----------- MOUSE_MOVED Message ---------- */
  286. static int MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  287. {
  288.     int MouseX = (int) p1 - GetClientLeft(wnd);
  289.     int MouseY = (int) p2 - GetClientTop(wnd);
  290.     RECT rc = ClientRect(wnd);
  291.     if (!InsideRect(p1, p2, rc))
  292.         return FALSE;
  293.     if (MouseY > wnd->wlines-1)
  294.         return FALSE;
  295.     if (ButtonDown)    {
  296.         SetAnchor(wnd, ButtonX+wnd->wleft, ButtonY+wnd->wtop);
  297.         TextMarking = TRUE;
  298.         SendMessage(NULL,MOUSE_TRAVEL,
  299.                 (PARAM)&WindowRect(wnd),0);
  300.         ButtonDown = FALSE;
  301.     }
  302.     if (TextMarking && !(WindowMoving || WindowSizing))    {
  303.         ExtendBlock(wnd, MouseX, MouseY);
  304.         return TRUE;
  305.     }
  306.     return FALSE;
  307. }
  308. static void StopMarking(WINDOW wnd)
  309. {
  310.     TextMarking = FALSE;
  311.     if (wnd->BlkBegLine > wnd->BlkEndLine)    {
  312.         swap(wnd->BlkBegLine, wnd->BlkEndLine);
  313.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  314.     }
  315.     if (wnd->BlkBegLine == wnd->BlkEndLine &&
  316.             wnd->BlkBegCol > wnd->BlkEndCol)
  317.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  318. }
  319. /* ----------- BUTTON_RELEASED Message ---------- */
  320. static int ButtonReleasedMsg(WINDOW wnd)
  321. {
  322.     if (isMultiLine(wnd))    {
  323.         ButtonDown = FALSE;
  324.         if (TextMarking && !(WindowMoving || WindowSizing))  {
  325.             /* release the mouse ouside the edit box */
  326.             SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  327.             StopMarking(wnd);
  328.             return TRUE;
  329.         }
  330.         else
  331.             PrevY = -1;
  332.     }
  333.     return FALSE;
  334. }
  335. /* ---- Process text block keys for multiline text box ---- */
  336. static void DoMultiLines(WINDOW wnd, int c, PARAM p2)
  337. {
  338.     if (isMultiLine(wnd))    {
  339.         if ((int)p2 & (LEFTSHIFT | RIGHTSHIFT))    {
  340.             int kx, ky;
  341.             SendMessage(NULL, CURRENT_KEYBOARD_CURSOR,
  342.                 (PARAM) &kx, (PARAM) &ky);
  343.             kx -= GetClientLeft(wnd);
  344.             ky -= GetClientTop(wnd);
  345.             switch (c)    {
  346.                 case HOME:
  347.                 case END:
  348.                 case CTRL_HOME:
  349.                 case CTRL_END:
  350.                 case PGUP:
  351.                 case PGDN:
  352.                 case CTRL_PGUP:
  353.                 case CTRL_PGDN:
  354.                 case UP:
  355.                 case DN:
  356.                 case FWD:
  357.                 case BS:
  358.                 case CTRL_FWD:
  359.                 case CTRL_BS:
  360.                     if (!KeyBoardMarking)    {
  361.                         if (TextBlockMarked(wnd))    {
  362.                             ClearTextBlock(wnd);
  363.                             SendMessage(wnd, PAINT, 0, 0);
  364.                         }
  365.                         KeyBoardMarking = TextMarking = TRUE;
  366.                         SetAnchor(wnd, kx+wnd->wleft,
  367.                                                 ky+wnd->wtop);
  368.                     }
  369.                     break;
  370.                 default:
  371.                     break;
  372.             }
  373.         }
  374.     }
  375. }
  376. /* ---------- page/scroll keys ----------- */
  377. static int DoScrolling(WINDOW wnd, int c, PARAM p2)
  378. {
  379.     switch (c)    {
  380.         case PGUP:
  381.         case PGDN:
  382.             if (isMultiLine(wnd))
  383.                 BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  384.             break;
  385.         case CTRL_PGUP:
  386.         case CTRL_PGDN:
  387.             BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  388.             break;
  389.         case HOME:
  390.             Home(wnd);
  391.             break;
  392.         case END:
  393.             End(wnd);
  394.             break;
  395.         case CTRL_FWD:
  396.             NextWord(wnd);
  397.             break;
  398.         case CTRL_BS:
  399.             PrevWord(wnd);
  400.             break;
  401.         case CTRL_HOME:
  402.             if (isMultiLine(wnd))    {
  403.                 SendMessage(wnd, SCROLLDOC, TRUE, 0);
  404.                 wnd->CurrLine = 0;
  405.                 wnd->WndRow = 0;
  406.             }
  407.             Home(wnd);
  408.             break;
  409.         case CTRL_END:
  410.             if (isMultiLine(wnd) &&
  411.                     wnd->WndRow+wnd->wtop+1 < wnd->wlines
  412.                         && wnd->wlines > 0) {
  413.                 SendMessage(wnd, SCROLLDOC, FALSE, 0);
  414.                 SetLinePointer(wnd, wnd->wlines-1);
  415.                 wnd->WndRow =
  416.                     min(ClientHeight(wnd)-1, wnd->wlines-1);
  417.                 Home(wnd);
  418.             }
  419.             End(wnd);
  420.             break;
  421.         case UP:
  422.             if (isMultiLine(wnd))
  423.                 Upward(wnd);
  424.             break;
  425.         case DN:
  426.             if (isMultiLine(wnd))
  427.                 Downward(wnd);
  428.             break;
  429.         case FWD:
  430.             Forward(wnd);
  431.             break;
  432.         case BS:
  433.             Backward(wnd);
  434.             break;
  435.         default:
  436.             return FALSE;
  437.     }
  438.     if (!KeyBoardMarking && TextBlockMarked(wnd))    {
  439.         ClearTextBlock(wnd);
  440.         SendMessage(wnd, PAINT, 0, 0);
  441.     }
  442.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  443.     return TRUE;
  444. }
  445. /* -------------- Del key ---------------- */
  446. static int DelKey(WINDOW wnd)
  447. {
  448.     char *currchar = CurrChar;
  449.     int repaint = *currchar == '\n';
  450.     if (TextBlockMarked(wnd))    {
  451.         SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  452.         SendMessage(wnd, PAINT, 0, 0);
  453.         return TRUE;
  454.     }
  455.     if (*(currchar+1) == '\0')
  456.         return TRUE;
  457.     strcpy(currchar, currchar+1);
  458.     if (repaint)    {
  459.         BuildTextPointers(wnd);
  460.         SendMessage(wnd, PAINT, 0, 0);
  461.     }
  462.     else    {
  463.         ModTextPointers(wnd, wnd->CurrLine+1, -1);
  464.         WriteTextLine(wnd, NULL, wnd->WndRow+wnd->wtop, FALSE);
  465.     }
  466.     wnd->TextChanged = TRUE;
  467.     return FALSE;
  468. }
  469. /* ------------ Tab key ------------ */
  470. static int TabKey(WINDOW wnd, PARAM p2)
  471. {
  472.     if (isMultiLine(wnd))    {
  473.         int insmd = wnd->InsertMode;
  474.         do  {
  475.             char *cc = CurrChar+1;
  476.             if (!insmd && *cc == '\0')
  477.                 break;
  478.             if (wnd->textlen == wnd->MaxTextLength)
  479.                 break;
  480.             SendMessage(wnd,KEYBOARD,insmd ? ' ' : FWD,0);
  481.         } while (wnd->CurrCol % cfg.Tabs);
  482.         return TRUE;
  483.     }
  484.     PostMessage(GetParent(wnd), KEYBOARD, '\t', p2);
  485.     return FALSE;
  486. }
  487. /* --------- All displayable typed keys ------------- */
  488. static void KeyTyped(WINDOW wnd, int c)
  489. {
  490.     char *currchar = CurrChar;
  491.     if ((c != '\n' && c < ' ') || (c & 0x1000))
  492.         /* ---- not recognized by editor --- */
  493.         return;
  494.     if (!isMultiLine(wnd) && TextBlockMarked(wnd))    {
  495.         ResetEditBox(wnd);
  496.         currchar = CurrChar;
  497.     }
  498.     if (*currchar == '\0')    {
  499.         /* ---- typing at end of text ---- */
  500.         if (currchar == wnd->text+wnd->MaxTextLength)    {
  501.             /* ---- typing at the end of maximum buffer ---- */
  502.             beep();
  503.             return;
  504.         }
  505.         /* --- insert a newline at end of text --- */
  506.         *currchar = '\n';
  507.         *(currchar+1) = '\0';
  508.         BuildTextPointers(wnd);
  509.     }
  510.     /* --- displayable char or newline --- */
  511.     if (c == '\n' || wnd->InsertMode ||    *currchar == '\n') {
  512.         /* ------ inserting the keyed character ------ */
  513.         if (wnd->text[wnd->textlen-1] != '\0')    {
  514.             /* --- the current text buffer is full --- */
  515.             if (wnd->textlen == wnd->MaxTextLength)    {
  516.                 /* --- text buffer is at maximum size --- */
  517.                 beep();
  518.                 return;
  519.             }
  520.             /* ---- increase the text buffer size ---- */
  521.             wnd->textlen += GROWLENGTH;
  522.             /* --- but not above maximum size --- */
  523.             if (wnd->textlen > wnd->MaxTextLength)
  524.                 wnd->textlen = wnd->MaxTextLength;
  525.             wnd->text = realloc(wnd->text, wnd->textlen+2);
  526.             wnd->text[wnd->textlen-1] = '\0';
  527.             currchar = CurrChar;
  528.         }
  529.         memmove(currchar+1, currchar, strlen(currchar)+1);
  530.         ModTextPointers(wnd, wnd->CurrLine+1, 1);
  531.         if (isMultiLine(wnd) && wnd->wlines > 1)
  532.             wnd->textwidth = max(wnd->textwidth,
  533.                 (int) (TextLine(wnd, wnd->CurrLine+1)-
  534.                 TextLine(wnd, wnd->CurrLine)));
  535.         else
  536.             wnd->textwidth = max(wnd->textwidth,
  537.                 strlen(wnd->text));
  538.         WriteTextLine(wnd, NULL,
  539.             wnd->wtop+wnd->WndRow, FALSE);
  540.     }
  541.     /* ----- put the char in the buffer ----- */
  542.     *currchar = c;
  543.     wnd->TextChanged = TRUE;
  544.     if (c == '\n')    {
  545.         wnd->wleft = 0;
  546.         BuildTextPointers(wnd);
  547.         End(wnd);
  548.         Forward(wnd);
  549.         SendMessage(wnd, PAINT, 0, 0);
  550.         return;
  551.     }
  552.     /* ---------- test end of window --------- */
  553.     if (WndCol == ClientWidth(wnd)-1)    {
  554.         int dif;
  555.         char *cp = currchar;
  556.         while (*cp != ' ' && cp != TextLine(wnd, wnd->CurrLine))
  557.             --cp;
  558.         if (!isMultiLine(wnd) ||
  559.             cp == TextLine(wnd, wnd->CurrLine) ||
  560.                 !wnd->WordWrapMode)
  561.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  562.         else    {
  563.             dif = 0;
  564.             if (c != ' ')    {
  565.                 dif = (int) (currchar - cp);
  566.                 wnd->CurrCol -= dif;
  567.                 SendMessage(wnd, KEYBOARD, DEL, 0);
  568.                 --dif;
  569.             }
  570.             SendMessage(wnd, KEYBOARD, '\r', 0);
  571.             currchar = CurrChar;
  572.             wnd->CurrCol = dif;
  573.             if (c == ' ')
  574.                 return;
  575.         }
  576.     }
  577.     /* ------ display the character ------ */
  578.     SetStandardColor(wnd);
  579.     PutWindowChar(wnd, c, WndCol, wnd->WndRow);
  580.     /* ----- advance the pointers ------ */
  581.     wnd->CurrCol++;
  582. }
  583. /* ------------ screen changing key strokes ------------- */
  584. static int DoKeyStroke(WINDOW wnd, int c, PARAM p2)
  585. {
  586.     switch (c)    {
  587.         case RUBOUT:
  588.             Backward(wnd);
  589.         case DEL:
  590.             if (DelKey(wnd))
  591.                 return TRUE;
  592.             break;
  593.         case CTRL_FIVE:    /* same as Shift+Tab */
  594.             if (!((int)p2 & (LEFTSHIFT | RIGHTSHIFT)))
  595.                 break;
  596.         case '\t':
  597.             if (TabKey(wnd, p2))
  598.                 return TRUE;
  599.             break;
  600.         case '\r':
  601.             if (!isMultiLine(wnd))    {
  602.                 PostMessage(GetParent(wnd), KEYBOARD, c, p2);
  603.                 break;
  604.             }
  605.             c = '\n';
  606.         default:
  607.             if (TextBlockMarked(wnd))    {
  608.                 SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  609.                 SendMessage(wnd, PAINT, 0, 0);
  610.             }
  611.             KeyTyped(wnd, c);
  612.             break;
  613.     }
  614.     return FALSE;
  615. }
  616. /* ----------- KEYBOARD Message ---------- */
  617. static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  618. {
  619.     int c = (int) p1;
  620.     if (WindowMoving || WindowSizing || ((int)p2 & ALTKEY))
  621.         return FALSE;
  622.     switch (c)    {
  623.         /* --- these keys get processed by lower classes --- */
  624.         case ESC:
  625.         case F1:
  626.         case F2:
  627.         case F3:
  628.         case F4:
  629.         case F5:
  630.         case F6:
  631.         case F7:
  632.         case F8:
  633.         case F9:
  634.         case F10:
  635.         case INS:
  636.         case SHIFT_INS:
  637.         case SHIFT_DEL:
  638.             return FALSE;
  639.         /* --- these keys get processed here --- */
  640.         case CTRL_FWD:
  641.         case CTRL_BS:
  642.         case CTRL_HOME:
  643.         case CTRL_END:
  644.         case CTRL_PGUP:
  645.         case CTRL_PGDN:
  646.             break;
  647.         default:
  648.             /* other ctrl keys get processed by lower classes */
  649.             if ((int)p2 & CTRLKEY)
  650.                 return FALSE;
  651.             /* --- all other keys get processed here --- */
  652.             break;
  653.     }
  654.     DoMultiLines(wnd, c, p2);
  655.     if (DoScrolling(wnd, c, p2))    {
  656.         if (KeyBoardMarking)
  657.             ExtendBlock(wnd, WndCol, wnd->WndRow);
  658.     }
  659.     else if (!TestAttribute(wnd, READONLY))    {
  660.         DoKeyStroke(wnd, c, p2);
  661.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  662.     }
  663.     return TRUE;
  664. }
  665. /* ----------- SHIFT_CHANGED Message ---------- */
  666. static void ShiftChangedMsg(WINDOW wnd, PARAM p1)
  667. {
  668.     if (!((int)p1 & (LEFTSHIFT | RIGHTSHIFT)) &&
  669.                                    KeyBoardMarking)    {
  670.         StopMarking(wnd);
  671.         KeyBoardMarking = FALSE;
  672.     }
  673. }
  674. /* ----------- ID_DELETETEXT Command ---------- */
  675. static void DeleteTextCmd(WINDOW wnd)
  676. {
  677.     if (TextBlockMarked(wnd))    {
  678.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  679.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  680.         int len = (int) (bel - bbl);
  681.         SaveDeletedText(wnd, bbl, len);
  682.         wnd->TextChanged = TRUE;
  683.         strcpy(bbl, bel);
  684.         wnd->CurrLine = TextLineNumber(wnd, bbl-wnd->BlkBegCol);
  685.         wnd->CurrCol = wnd->BlkBegCol;
  686.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  687.         if (wnd->WndRow < 0)    {
  688.             wnd->wtop = wnd->BlkBegLine;
  689.             wnd->WndRow = 0;
  690.         }
  691.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  692.         ClearTextBlock(wnd);
  693.         BuildTextPointers(wnd);
  694.     }
  695. }
  696. /* ----------- ID_CLEAR Command ---------- */
  697. static void ClearCmd(WINDOW wnd)
  698. {
  699.     if (TextBlockMarked(wnd))    {
  700.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  701.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  702.         int len = (int) (bel - bbl);
  703.         SaveDeletedText(wnd, bbl, len);
  704.         wnd->CurrLine = TextLineNumber(wnd, bbl);
  705.         wnd->CurrCol = wnd->BlkBegCol;
  706.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  707.         if (wnd->WndRow < 0)    {
  708.             wnd->WndRow = 0;
  709.             wnd->wtop = wnd->BlkBegLine;
  710.         }
  711.         /* ------ change all text lines in block to \n ----- */
  712.         while (bbl < bel)    {
  713.             char *cp = strchr(bbl, '\n');
  714.             if (cp > bel)
  715.                 cp = bel;
  716.             strcpy(bbl, cp);
  717.             bel -= (int) (cp - bbl);
  718.             bbl++;
  719.         }
  720.         ClearTextBlock(wnd);
  721.         BuildTextPointers(wnd);
  722.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  723.         SendMessage(wnd, PAINT, 0, 0);
  724.         wnd->TextChanged = TRUE;
  725.     }
  726. }
  727. /* ----------- ID_UNDO Command ---------- */
  728. static void UndoCmd(WINDOW wnd)
  729. {
  730.     if (wnd->DeletedText != NULL)    {
  731.         PasteText(wnd, wnd->DeletedText, wnd->DeletedLength);
  732.         free(wnd->DeletedText);
  733.         wnd->DeletedText = NULL;
  734.         wnd->DeletedLength = 0;
  735.         SendMessage(wnd, PAINT, 0, 0);
  736.     }
  737. }
  738. /* ----------- ID_PARAGRAPH Command ---------- */
  739. static void ParagraphCmd(WINDOW wnd)
  740. {
  741.     int bc, ec, fl, el, Blocked;
  742.     char *bl, *bbl, *bel, *bb;
  743.  
  744.     el = wnd->BlkEndLine;
  745.     ec = wnd->BlkEndCol;
  746.     if (!TextBlockMarked(wnd))    {
  747.         Blocked = FALSE;
  748.         /* ---- forming paragraph from cursor position --- */
  749.         fl = wnd->wtop + wnd->WndRow;
  750.         bbl = bel = bl = TextLine(wnd, wnd->CurrLine);
  751.         if ((bc = wnd->CurrCol) >= ClientWidth(wnd))
  752.             bc = 0;
  753.         Home(wnd);
  754.         /* ---- locate the end of the paragraph ---- */
  755.         while (*bel)    {
  756.             int blank = TRUE;
  757.             char *bll = bel;
  758.             /* --- blank line marks end of paragraph --- */
  759.             while (*bel && *bel != '\n')    {
  760.                 if (*bel != ' ')
  761.                     blank = FALSE;
  762.                 bel++;
  763.             }
  764.             if (blank)    {
  765.                 bel = bll;
  766.                 break;
  767.             }
  768.             if (*bel)
  769.                 bel++;
  770.         }
  771.         if (bel == bbl)    {
  772.             SendMessage(wnd, KEYBOARD, DN, 0);
  773.             return;
  774.         }
  775.         if (*bel == '\0')
  776.             --bel;
  777.         if (*bel == '\n')
  778.             --bel;
  779.     }
  780.     else    {
  781.         /* ---- forming paragraph from marked block --- */
  782.         Blocked = TRUE;
  783.         bbl = TextLine(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  784.         bel = TextLine(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  785.         fl = wnd->BlkBegLine;
  786.         bc = wnd->CurrCol = wnd->BlkBegCol;
  787.         wnd->CurrLine = fl;
  788.         if (fl < wnd->wtop)
  789.             wnd->wtop = fl;
  790.         wnd->WndRow = fl - wnd->wtop;
  791.         SendMessage(wnd, KEYBOARD, '\r', 0);
  792.         el++, fl++;
  793.         if (bc != 0)    {
  794.             SendMessage(wnd, KEYBOARD, '\r', 0);
  795.             el++, fl ++;
  796.         }
  797.         bc = 0;
  798.         bl = TextLine(wnd, fl);
  799.         wnd->CurrLine = fl;
  800.         bbl = bl + bc;
  801.         bel = TextLine(wnd, el) + ec;
  802.     }
  803.     /* --- change all newlines in block to spaces --- */
  804.     while (CurrChar < bel)    {
  805.         if (*CurrChar == '\n')    {
  806.             *CurrChar = ' ';
  807.             wnd->CurrLine++;
  808.             wnd->CurrCol = 0;
  809.         }
  810.         else
  811.             wnd->CurrCol++;
  812.     }
  813.     /* ---- insert newlines at new margin boundaries ---- */
  814.     bb = bbl;
  815.     while (bbl < bel)    {
  816.         bbl++;
  817.         if ((int)(bbl - bb) == ClientWidth(wnd)-1)    {
  818.             while (*bbl != ' ' && bbl > bb)
  819.                 --bbl;
  820.             if (*bbl != ' ')    {
  821.                 bbl = strchr(bbl, ' ');
  822.                 if (bbl == NULL || bbl >= bel)
  823.                     break;
  824.             }
  825.             *bbl = '\n';
  826.             bb = bbl+1;
  827.         }
  828.     }
  829.     ec = (int)(bel - bb);
  830.     BuildTextPointers(wnd);
  831.     if (Blocked)    {
  832.         /* ---- position cursor at end of new paragraph ---- */
  833.         if (el < wnd->wtop ||
  834.                 wnd->wtop + ClientHeight(wnd) < el)
  835.             wnd->wtop = el-ClientHeight(wnd);
  836.         if (wnd->wtop < 0)
  837.             wnd->wtop = 0;
  838.         wnd->WndRow = el - wnd->wtop;
  839.         wnd->CurrLine = el;
  840.         wnd->CurrCol = ec;
  841.         SendMessage(wnd, KEYBOARD, '\r', 0);
  842.         SendMessage(wnd, KEYBOARD, '\r', 0);
  843.     }
  844.     else    {
  845.         /* --- put cursor back at beginning --- */
  846.         wnd->CurrLine = TextLineNumber(wnd, bl);
  847.         wnd->CurrCol = bc;
  848.         if (fl < wnd->wtop)
  849.             wnd->wtop = fl;
  850.         wnd->WndRow = fl - wnd->wtop;
  851.     }
  852.     SendMessage(wnd, PAINT, 0, 0);
  853.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  854.     wnd->TextChanged = TRUE;
  855.     BuildTextPointers(wnd);
  856. }
  857. /* ----------- COMMAND Message ---------- */
  858. static int CommandMsg(WINDOW wnd, PARAM p1)
  859. {
  860.     switch ((int)p1)    {
  861.         case ID_DELETETEXT:
  862.             DeleteTextCmd(wnd);
  863.             return TRUE;
  864.         case ID_CLEAR:
  865.             ClearCmd(wnd);
  866.             return TRUE;
  867.         case ID_UNDO:
  868.             UndoCmd(wnd);
  869.             return TRUE;
  870.         case ID_PARAGRAPH:
  871.             ParagraphCmd(wnd);
  872.             return TRUE;
  873.         default:
  874.             break;
  875.     }
  876.     return FALSE;
  877. }
  878. /* ---------- CLOSE_WINDOW Message ----------- */
  879. static void CloseWindowMsg(WINDOW wnd)
  880. {
  881.     SendMessage(NULL, HIDE_CURSOR, 0, 0);
  882.     if (wnd->DeletedText != NULL)
  883.         free(wnd->DeletedText);
  884. }
  885. /* ------- Window processing module for EDITBOX class ------ */
  886. int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  887. {
  888.     int rtn;
  889.     switch (msg)    {
  890.         case CREATE_WINDOW:
  891.             return CreateWindowMsg(wnd);
  892.         case ADDTEXT:
  893.             return AddTextMsg(wnd, p1, p2);
  894.         case SETTEXT:
  895.             return SetTextMsg(wnd, p1);
  896.         case CLEARTEXT:
  897.             ResetEditBox(wnd);
  898.             break;
  899.         case GETTEXT:
  900.             return GetTextMsg(wnd, p1, p2);
  901.         case SETTEXTLENGTH:
  902.             return SetTextLengthMsg(wnd, (unsigned) p1);
  903.         case KEYBOARD_CURSOR:
  904.             return KeyboardCursorMsg(wnd, p1, p2);
  905.         case SETFOCUS:
  906.         case PAINT:
  907.         case MOVE:
  908.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  909.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  910.             return rtn;
  911.         case SIZE:
  912.             return SizeMsg(wnd, p1, p2);
  913.         case SCROLL:
  914.             return ScrollMsg(wnd, p1);
  915.         case HORIZSCROLL:
  916.             return HorizScrollMsg(wnd, p1);
  917.         case SCROLLPAGE:
  918.             return ScrollPageMsg(wnd, p1);
  919.         case HORIZPAGE:
  920.             return HorizPageMsg(wnd, p1);
  921.         case LEFT_BUTTON:
  922.             if (LeftButtonMsg(wnd, p1, p2))
  923.                 return TRUE;
  924.             break;
  925.         case MOUSE_MOVED:
  926.             if (MouseMovedMsg(wnd, p1, p2))
  927.                 return TRUE;
  928.             break;
  929.         case BUTTON_RELEASED:
  930.             if (ButtonReleasedMsg(wnd))
  931.                 return TRUE;
  932.             break;
  933.         case KEYBOARD:
  934.             if (KeyboardMsg(wnd, p1, p2))
  935.                 return TRUE;
  936.             break;
  937.         case SHIFT_CHANGED:
  938.             ShiftChangedMsg(wnd, p1);
  939.             break;
  940.         case COMMAND:
  941.             if (CommandMsg(wnd, p1))
  942.                 return TRUE;
  943.             break;
  944.         case CLOSE_WINDOW:
  945.             CloseWindowMsg(wnd);
  946.             break;
  947.         default:
  948.             break;
  949.     }
  950.     return BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  951. }
  952. /* ------ save deleted text for the Undo command ------ */
  953. static void SaveDeletedText(WINDOW wnd, char *bbl, int len)
  954. {
  955.     wnd->DeletedLength = len;
  956.     if ((wnd->DeletedText=realloc(wnd->DeletedText,len))!=NULL)
  957.         memmove(wnd->DeletedText, bbl, len);
  958. }
  959. /* ---- cursor right key: right one character position ---- */
  960. static void Forward(WINDOW wnd)
  961. {
  962.     char *cc = CurrChar+1;
  963.     if (*cc == '\0')
  964.         return;
  965.     if (*CurrChar == '\n')    {
  966.         Home(wnd);
  967.         Downward(wnd);
  968.     }
  969.     else    {
  970.         wnd->CurrCol++;
  971.         if (WndCol == ClientWidth(wnd))
  972.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  973.     }
  974. }
  975. /* ----- stick the moving cursor to the end of the line ---- */
  976. static void StickEnd(WINDOW wnd)
  977. {
  978.     char *cp = TextLine(wnd, wnd->CurrLine);
  979.     char *cp1 = strchr(cp, '\n');
  980.     int len = cp1 ? (int) (cp1 - cp) : 0;
  981.     wnd->CurrCol = min(len, wnd->CurrCol);
  982.     if (wnd->wleft > wnd->CurrCol)    {
  983.         wnd->wleft = max(0, wnd->CurrCol - 4);
  984.         SendMessage(wnd, PAINT, 0, 0);
  985.     }
  986.     else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd))    {
  987.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  988.         SendMessage(wnd, PAINT, 0, 0);
  989.     }
  990. }
  991. /* --------- cursor down key: down one line --------- */
  992. static void Downward(WINDOW wnd)
  993. {
  994.     if (isMultiLine(wnd) &&
  995.             wnd->WndRow+wnd->wtop+1 < wnd->wlines)  {
  996.         wnd->CurrLine++;
  997.         if (wnd->WndRow == ClientHeight(wnd)-1)
  998.             SendMessage(wnd, SCROLL, TRUE, 0);
  999.         wnd->WndRow++;
  1000.         StickEnd(wnd);
  1001.     }
  1002. }
  1003. /* -------- cursor up key: up one line ------------ */
  1004. static void Upward(WINDOW wnd)
  1005. {
  1006.     if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1007.         if (wnd->CurrLine > 0)
  1008.             --wnd->CurrLine;
  1009.         if (wnd->WndRow == 0)
  1010.             SendMessage(wnd, SCROLL, FALSE, 0);
  1011.         --wnd->WndRow;
  1012.         StickEnd(wnd);
  1013.     }
  1014. }
  1015. /* ---- cursor left key: left one character position ---- */
  1016. static void Backward(WINDOW wnd)
  1017. {
  1018.     if (wnd->CurrCol)    {
  1019.         if (wnd->CurrCol-- <= wnd->wleft)
  1020.             if (wnd->wleft != 0)
  1021.                 SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  1022.     }
  1023.     else if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1024.         Upward(wnd);
  1025.         End(wnd);
  1026.     }
  1027. }
  1028. /* -------- End key: to end of line ------- */
  1029. static void End(WINDOW wnd)
  1030. {
  1031.     while (*CurrChar && *CurrChar != '\n')
  1032.         ++wnd->CurrCol;
  1033.     if (WndCol >= ClientWidth(wnd))    {
  1034.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1035.         SendMessage(wnd, PAINT, 0, 0);
  1036.     }
  1037. }
  1038. /* -------- Home key: to beginning of line ------- */
  1039. static void Home(WINDOW wnd)
  1040. {
  1041.     wnd->CurrCol = 0;
  1042.     if (wnd->wleft != 0)    {
  1043.         wnd->wleft = 0;
  1044.         SendMessage(wnd, PAINT, 0, 0);
  1045.     }
  1046. }
  1047. /* -- Ctrl+cursor right key: to beginning of next word -- */
  1048. static void NextWord(WINDOW wnd)
  1049. {
  1050.     int savetop = wnd->wtop;
  1051.     int saveleft = wnd->wleft;
  1052.     ClearVisible(wnd);
  1053.     while (!isWhite(*CurrChar))    {
  1054.         char *cc = CurrChar+1;
  1055.         if (*cc == '\0')
  1056.             break;
  1057.         Forward(wnd);
  1058.     }
  1059.     while (isWhite(*CurrChar))    {
  1060.         char *cc = CurrChar+1;
  1061.         if (*cc == '\0')
  1062.             break;
  1063.         Forward(wnd);
  1064.     }
  1065.     SetVisible(wnd);
  1066.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1067.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1068.         SendMessage(wnd, PAINT, 0, 0);
  1069. }
  1070. /* -- Ctrl+cursor left key: to beginning of previous word -- */
  1071. static void PrevWord(WINDOW wnd)
  1072. {
  1073.     int savetop = wnd->wtop;
  1074.     int saveleft = wnd->wleft;
  1075.     ClearVisible(wnd);
  1076.     Backward(wnd);
  1077.     while (isWhite(*CurrChar))    {
  1078.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1079.             break;
  1080.         Backward(wnd);
  1081.     }
  1082.     while (!isWhite(*CurrChar))    {
  1083.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1084.             break;
  1085.         Backward(wnd);
  1086.     }
  1087.     if (isWhite(*CurrChar))
  1088.         Forward(wnd);
  1089.     SetVisible(wnd);
  1090.     if (wnd->wleft != saveleft)
  1091.         if (wnd->CurrCol >= saveleft)
  1092.             if (wnd->CurrCol - saveleft < ClientWidth(wnd))
  1093.                 wnd->wleft = saveleft;
  1094.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1095.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1096.         SendMessage(wnd, PAINT, 0, 0);
  1097. }
  1098. /* ----- reset the text attributes of an EDITBOX ------- */
  1099. static void ResetEditBox(WINDOW wnd)
  1100. {
  1101.     unsigned blen = EditBufLen(wnd)+2;
  1102.     wnd->text = realloc(wnd->text, blen);
  1103.     memset(wnd->text, 0, blen);
  1104.     wnd->wlines = 0;
  1105.     wnd->CurrLine = 0;
  1106.     wnd->CurrCol = 0;
  1107.     wnd->WndRow = 0;
  1108.     wnd->wleft = 0;
  1109.     wnd->wtop = 0;
  1110.     wnd->textwidth = 0;
  1111.     wnd->TextChanged = FALSE;
  1112.     ClearTextPointers(wnd);
  1113.     ClearTextBlock(wnd);
  1114. }
  1115. /* ----- modify text pointers from a specified position
  1116.                 by a specified plus or minus amount ----- */
  1117. static void ModTextPointers(WINDOW wnd, int lineno, int var)
  1118. {
  1119.     while (lineno < wnd->wlines)
  1120.         *((wnd->TextPointers) + lineno++) += var;
  1121. }
  1122.  
  1123.